%matplotlib inline
import seaborn
import scipy, scipy.signal, IPython.display as ipd, matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = (13, 4)
In the examples below, listen to each interval, and compare intervals both visually and aurally across tuning systems. Try to listen for dissonance and beat frequencies, or absence thereof.
In twelve-tone equal temperament, all twelve semitones within the octave have the same width. With this tuning system, expressed as a frequency ratio, the interval of one semitone is $2^{1/12}$. Expressed in cents, this same interval is defined to be 100 cents. Therefore, the octave has 1200 cents.
In just intonation, the frequency ratio is expressed as a fraction between two small integers, e.g. 3:2, 4:3. As a result, the higher harmonic partials between two notes will overlap, resulting in a consonant interval that is pleasing to the ear. In 5-limit just tuning, these fractions are expressed with prime factors no larger than 5, i.e. {2, 3, 5}. In 7-limit just tuning, these fractions are expressed with prime factors no larger than 7, i.e. {2, 3, 5, 7}. For example, 7:4 is a 7-limit interval, but it is not a 5-limit interval.
In Pythagorean tuning, every frequency ratio is based upon the ratio 3:2. To find that ratio, from one note in the interval, step around the Circle of Fifths until you reach the other note in the interval, multiplying (if stepping forward) or dividing (if stepping backward) by 3/2 with each step. Finally, multiply or divide by 2 enough times to return to the octave of interest.
Global parameters for this notebook:
T = 5.0 # duration in seconds
fs = 24000 # sampling rate in Hertz
fcutoff = 4000 # frequency cutoff for filter
Functions used to create the sounds and figures:
def simulate_tone(f0, harmonics=None):
if harmonics is None:
harmonics = [1]
t = scipy.linspace(0, T, T*fs, endpoint=False)
x = sum(v*scipy.sin(2*scipy.pi*i*f0*t) for i, v in enumerate(harmonics, 1))
return x
def filter_tone(x, fcutoff=None):
if fcutoff is None:
fcutoff = fs/2.0
h = scipy.signal.firwin(55, 2*float(fcutoff)/fs)
y = scipy.convolve(x, h)
return y
def make_double_stop(ratio, f0=440, harmonics=None):
if harmonics is None:
harmonics = [1]
f1 = ratio*f0
x0 = filter_tone(simulate_tone(f0, harmonics=harmonics), fcutoff=fcutoff)
x1 = filter_tone(simulate_tone(f1, harmonics=harmonics), fcutoff=fcutoff)
X0 = scipy.fft(x0)
X1 = scipy.fft(x1)
N = len(X0)
f = scipy.linspace(0, fs, N, endpoint=False)
plt.semilogy(f, abs(X0), marker='o', linewidth=1)
plt.semilogy(f, abs(X1), color='r', linewidth=1)
plt.xlim(xmax=(len(harmonics)+1)*(f1 if ratio > 1 else f0))
plt.ylim(ymin=0.1)
plt.xlabel('Frequency (Hz)')
plt.legend(('f0 = %.2f Hz' % f0, 'f0 = %.2f Hz' % f1))
print 'ratio:', ratio
print 'cents:', scipy.log2(ratio)*1200
return ipd.Audio(x0 + x1, rate=fs)
Within each section below, the intervals are provided in order of interval width from lowest to highest.
make_double_stop(1)
harmonics = [1.0, 0.5]
Just intonation or equal temperament, 12 semitones, 1200 cents:
make_double_stop(2, harmonics=harmonics)
Pythagorean tuning, twelve steps forward on the Circle of Fifths. In Pythagorean tuning, multiply the fundamental frequency by 3/2 twelve times, and then divide by two enough times to return to the octave of interest:
make_double_stop(531441.0/262144, harmonics=harmonics)
The Pythagorean comma, the degree of inconsistency when trying to define a twelve-tone scale using only perfect fifths, is about 1.0136 when expressed as a frequency ratio:
harmonics = [1.0, 0.1, 0.1]
Equal temperament, seven semitones, 700 cents:
make_double_stop(2**(7.0/12), harmonics=harmonics)
Just intonation or Pythagorean tuning, one step forward on the Circle of Fifths:
make_double_stop(3.0/2, harmonics=harmonics)
harmonics = [1.0, 0.01, 0.1, 0.1]
Just intonation or Pythagorean tuning, one step backward on the Circle of Fifths:
make_double_stop(4.0/3, harmonics=harmonics)
Equal temperament, five semitones:
make_double_stop(2**(5.0/12), harmonics=harmonics)
harmonics = [1.0, 0.01, 0.1, 0.01, 0.1]
Just intonation:
make_double_stop(5.0/3, harmonics=harmonics)
Equal temperament, i.e. nine semitones:
make_double_stop(2**(9.0/12), harmonics=harmonics)
Pythagorean tuning, three steps forward on the Circle of Fifths:
make_double_stop(27.0/16, harmonics=harmonics)
harmonics = [1.0, 0.01, 0.01, 0.1, 0.1]
Just intonation:
make_double_stop(5.0/4, harmonics=harmonics)
Equal temperament, four semitones:
make_double_stop(2**(4.0/12), harmonics=harmonics)
Pythagorean tuning, four steps forward on the Circle of Fifths:
make_double_stop(81.0/64, harmonics=harmonics)
harmonics = [1.0, 0.01, 0.01, 0.01, 0.1, 0.1]
Pythagorean tuning, three steps backward on the Circle of Fifths:
make_double_stop(32.0/27, harmonics=harmonics)
Equal temperament, three semitones:
make_double_stop(2**(3.0/12), harmonics=harmonics)
Just intonation:
make_double_stop(6.0/5, harmonics=harmonics)
harmonics = [1.0, 0.001, 0.001, 0.001, 0.01, 0.001, 0.001, 0.01]
Pythagorean tuning, four steps backward on the Circle of Fifths:
make_double_stop(128.0/81, harmonics=harmonics)
Equal temperament, eight semitones:
make_double_stop(2**(8.0/12), harmonics=harmonics)
Just intonation:
make_double_stop(8.0/5, harmonics=harmonics)
harmonics = [0.01,] * 16
harmonics[0] = 1.0
harmonics[14] = 0.1
harmonics[15] = 0.1
Just intonation:
make_double_stop(16.0/15, harmonics=harmonics)
Equal temperament, one semitone:
make_double_stop(2**(1.0/12), harmonics=harmonics)
harmonics = [1.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.1, 0.1]
Equal temperament, two semitones:
make_double_stop(2**(2.0/12), harmonics=harmonics)
Just intonation or Pythagorean tuning, two steps forward on the Circle of Fifths:
make_double_stop(9.0/8, harmonics=harmonics)
harmonics = [1.0,] * 15
make_double_stop(15.0/8, harmonics=harmonics)
Harmonic seventh, or subminor seventh:
make_double_stop(7.0/4)
Small just minor seventh:
make_double_stop(16.0/9)
Large just minor seventh:
make_double_stop(9.0/5)
Diminished fifth, Pythagorean tuning, six steps backward on the Circle of Fifths:
make_double_stop(1024.0/729)
Augmented fourth:
make_double_stop(45.0/32)
Equal temperament, six semitones, 600 cents:
make_double_stop(2**(6.0/12))
Diminished fifth:
make_double_stop(64.0/45)
Augmented fourth, Pythagorean tuning, six steps forward on the Circle of Fifths:
make_double_stop(729.0/512)